package ai;

import java.text.NumberFormat;

import org.encog.ml.data.MLDataSet;

import ai.exemples.MLDataPairFactory;
import ai.exemples.MLDataSetFactory;
import ai.exemples.NotEnoughDataInFilesException;
import ai.reseaux.PerceptronCache;
import ai.reseaux.PerceptronSimple;
import ai.reseaux.ReseauAbstract;

public class Main {
	
	/**
	 * @param args
	 * 1er argument : 'test' si on veut effecteur un test 'validation' pour une validation
	 * 2eme argument : 'simple' pour un perceptron sans couche caché, 'cache' avec couche caché
	 * 3eme argument : le Taux d'apprentissage
	 * 4eme argument : le nombre de donnée d'apprentissage <= 40000
	 * @throws NotEnoughDataInFilesException
	 */
    public static void main(String[] args) throws NotEnoughDataInFilesException {
    	
    	//arguments par défaut
    	boolean test = true;
    	boolean simple = true;
    	double learningRate = 0.01;
    	int iterations = 100;
    	
    	//vérifier qu'il y a le bon nombre d'arguments
    	if (args.length != 4) {
    		System.out.println("Erreur : pas le bon nombre d'arguments");
    		System.out.println("Usage :");
    		System.out.println("1er argument : 'test' si on veut effecteur un test 'validation' pour une validation");
    		System.out.println("2eme argument : 'simple' pour un perceptron sans couche caché, 'cache' avec couche caché");
    		System.out.println("3eme argument : le Taux d'apprentissage (entre 0.0 et 1.0)");
    		System.out.println("4eme argument : le nombre de donnée d'apprentissage <= 40000");
    		System.exit(1);
    	}
    	
    	//vérifier le premier argument
    	if (args[0].equals("test")) {
    		test = true;
    	} else if (args[0].equals("validation")) {
    		test = false;
    	} else {
    		System.out.println("Erreur : 1er argument invalide");
    		System.out.println("Usage :");
    		System.out.println("1er argument : 'test' si on veut effecteur un test 'validation' pour une validation");
    		System.exit(1);
    	}
    	
    	//vérifier second argument
    	if (args[1].equals("simple")) {
    		simple = true;
    	} else if (args[1].equals("cache")) {
    		simple = false;
    	} else {
    		System.out.println("Erreur : 2eme argument invalide");
    		System.out.println("Usage :");
    		System.out.println("2eme argument : 'simple' pour un perceptron sans couche caché, 'cache' avec couche caché");
    		System.exit(1);
    	}
    	
    	//vérifier 3ème argument
    	NumberFormat nf = NumberFormat.getInstance();
    	try {
    		learningRate = nf.parse(args[2]).doubleValue();
    	} catch (Exception e) {
    		System.out.println("Erreur : 3eme argument invalide");
    		System.out.println("Usage :");
    		System.out.println("3eme argument : le Taux d'apprentissage (entre 0.0 et 1.0)");
    		System.exit(1);
		}
    	if (!( learningRate > 0.0) || !( learningRate < 1.0)) {
    		System.out.println("Erreur : 3eme argument invalide");
    		System.out.println("Usage :");
    		System.out.println("3eme argument : le Taux d'apprentissage (entre 0.0 et 1.0)");
    		System.exit(1);
    	}
    	
    	//vérifier 4ème argument
    	try {
    		iterations = Integer.parseInt(args[3]);
    	} catch (Exception e) {
    		System.out.println("Erreur : 4eme argument invalide");
    		System.out.println("Usage :");
    		System.out.println("4eme argument : le nombre de donnée d'apprentissage <= 40000");
    		System.exit(1);
		}
    	if (!(iterations > 0 ) || !(iterations <= 40000)) {
    		System.out.println("Erreur : 4eme argument invalide");
    		System.out.println("Usage :");
    		System.out.println("4eme argument : le nombre de donnée d'apprentissage <= 40000");
    		System.exit(1);
    	}
    	
    	//Créer un reseau
    	ReseauAbstract network = (simple) ? new PerceptronSimple() : new PerceptronCache();
    	
    	//Créer des données d'apprentissage
    	MLDataPairFactory pairFactory = new MLDataPairFactory("./Ressources/train-images", "./Ressources/train-labels");
    	MLDataSetFactory factory = new MLDataSetFactory(pairFactory);
    	MLDataSet trainingSet = factory.getDataSet(iterations);
    	System.out.println("Données d'apprentissage chargées");
    	
    	//faire apprendre le reseau
    	double learningError = network.learn(trainingSet, learningRate, iterations);
    	System.out.println("Fin de l'apprentissage; erreur = " + learningError);
    	
    	//charger les données de test ou de validation
    	pairFactory = (test) ? new MLDataPairFactory("./Ressources/test-images", "./Ressources/test-labels") : 
    		new MLDataPairFactory("./Ressources/validation-images", "./Ressources/validation-labels");
    	factory = new MLDataSetFactory(pairFactory);
    	MLDataSet testSet = factory.getDataSet();
    	System.out.println("Données de tests chargées");

    	//faire les tests
    	double testError = network.test(testSet);
    	System.out.println("Fin du test ; erreur = " + testError);
    }
}
